/**
  ******************************************************************************
  * @file    si2c_sht3x2x.c 
  * @author  make
  * @version V1.0.0
  * @date    2020.10.09
  * @brief   src program body
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "si2c_comm.h"
#include "tskcfg.h"
#include "bsp.h"

#define SGP30_ADDR_BASE         (0x58u)
#define	SGP30_ADDR_WRITE	      (SGP30_ADDR_BASE<<1)
#define	SGP30_ADDR_READ		      (SGP30_ADDR_WRITE+1)

#define sgp30_delay(x)          vTaskDelay(x)
#define byte_delay(x)           vTaskDelay(x)

__inline static void sgp30_sda_to_in(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};

	GPIO_InitStruct.Pin  = SGP30_SDA_PIN;
	GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}

__inline static void sgp30_sda_to_out(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};

	GPIO_InitStruct.Pin   = SGP30_SDA_PIN;
	GPIO_InitStruct.Mode  = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	GPIO_InitStruct.Pull  = GPIO_PULLUP;
	HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}

__inline static void sgp30_si2c_delay(void)
{
//  uint16_t delay_time=20;

//	while(delay_time--); /*7 400khz , 8 370khz*/
  sgp30_delay(2);
}

__inline static void sgp30_si2c_start(void)
{
  sgp30_sda_h();
	sgp30_scl_h();
  sgp30_si2c_delay();
  
	sgp30_sda_l();      /* sda一个下降沿 */
  sgp30_si2c_delay();
	
	sgp30_scl_l();
  sgp30_si2c_delay();
}

__inline static void sgp30_si2c_stop(void)
{
	sgp30_sda_l();
	sgp30_scl_h();
	sgp30_si2c_delay();

	sgp30_sda_h();      /* sda一个上升沿 */
  sgp30_si2c_delay();
}

__inline static uint8_t sgp30_si2c_write_byte(uint8_t dat)  /* 18 */
{
	uint8_t i, ack;

	sgp30_scl_l();                   /* 保证scl处于低 */

	for(i=0; i<8; i++)
	{
		if(0x80 & dat)
		{
			sgp30_sda_h();
		}
		else
		{
			sgp30_sda_l();
		}

		dat <<= 1;

		sgp30_scl_h();                 /* scl拉高 锁存数据 */
    sgp30_si2c_delay();

		sgp30_scl_l();                 /* scl拉低 准备数据 */
    sgp30_si2c_delay();
	}

  sgp30_sda_to_in();               /*释放data*/

  sgp30_scl_h();                   /*第9个时钟的上升沿*/
	sgp30_si2c_delay();

  if(sgp30_sda_r() != 0)
	{
		ack = SI2C_NACK;
	}
	else
	{
		ack = SI2C_ACK;
	}
	
  sgp30_scl_l();                   /*第9个时钟的下降沿*/
	sgp30_sda_to_out();              /*重新控制总线*/
//  sgp30_si2c_delay();
	
	byte_delay(5);
	
  return ack;
}

__inline static uint8_t sgp30_si2c_read_byte(uint8_t ack)
{
	uint8_t i;
	uint8_t dat;

	dat = 0;

	sgp30_scl_l();             /* 保证scl处于低 */

	sgp30_sda_to_in();

	for(i=0; i<8; i++)
	{
		sgp30_scl_h();                  /* scl拉高后,读出数据 */
    sgp30_si2c_delay();

		dat <<= 1;

		if(sgp30_sda_r() != 0)
		{
			dat |= 0x01;
		}
		else
		{
			dat &= 0xfe;
		}

		sgp30_scl_l();                  /* scl拉低,待对方准备数据 */
    sgp30_si2c_delay();
	}
	
	sgp30_sda_to_out();
	
	if(ack != SI2C_ACK)
	{
		sgp30_sda_h();  /* SI2C_NACK */
	}
	else
	{
		sgp30_sda_l();  /* SI2C_ACK */
	}
	
  sgp30_scl_h();
  sgp30_si2c_delay();             /*发送ack*/
	
  sgp30_scl_l();
//  sgp30_si2c_delay();
	
	byte_delay(5);
	return dat;
}

static uint8_t sgp30_si2c_send_cmd(uint8_t addr, uint16_t cmd)
{
	sgp30_si2c_start();
	
	if(sgp30_si2c_write_byte(addr) != SI2C_ACK)
	{
		sgp30_si2c_stop();
		return 1;
	}
	
	if(sgp30_si2c_write_byte((uint8_t)(cmd>>8)) != SI2C_ACK)
	{
		sgp30_si2c_stop();
		return 2;
	}
	
	if(sgp30_si2c_write_byte((uint8_t)cmd) != SI2C_ACK)
	{
		sgp30_si2c_stop();
		return 3;
	}
	
	sgp30_si2c_stop();
	
	return 0;
}

void Sgp30_ResetCmd(void)
{
	sgp30_si2c_start();
  
  sgp30_si2c_write_byte(0x00u);
  
  sgp30_si2c_write_byte(0x06u);
	
	sgp30_si2c_stop();
	
	vTaskDelay(10);
}

uint8_t Sgp30_ReInit(void)
{
	if(sgp30_si2c_send_cmd(SGP30_ADDR_WRITE, 0x2003u) != 0)
	{
		return 2;
	}
	
  vTaskDelay(500);
  
	return 0;
}

uint8_t Sgp30_GetSingleMeasure(volatile uint16_t *CO2, volatile uint16_t *TVOC)
{
	uint8_t buf[6];
	
	if(sgp30_si2c_send_cmd(SGP30_ADDR_WRITE, 0x2008u) != 0)
	{
		return 1;
	}
		
	sgp30_delay(15);
	
	sgp30_si2c_start();
		
	if(sgp30_si2c_write_byte(SGP30_ADDR_READ) != SI2C_ACK)
	{
		return 2;
	}
	
	buf[0] = sgp30_si2c_read_byte(SI2C_ACK);
	buf[1] = sgp30_si2c_read_byte(SI2C_ACK);
	buf[2] = sgp30_si2c_read_byte(SI2C_ACK);
	
	buf[3] = sgp30_si2c_read_byte(SI2C_ACK);
	buf[4] = sgp30_si2c_read_byte(SI2C_ACK);
	buf[5] = sgp30_si2c_read_byte(SI2C_NACK);
	
	sgp30_si2c_stop();
	
	if((sensor_crc8(buf, 0xFF) != buf[2]) || (sensor_crc8(&buf[3], 0xFF) != buf[5]))
	{
		return 3;
	}
	
	*CO2 = (buf[0]<<8)|buf[1];
	*TVOC = (buf[3]<<8)|(buf[4]);
	
	return 0;
}
